// 自动完成

// bbsCode的自动完成数据
import {EditorSelection} from "@codemirror/state";

/**
 * 自动完成匹配方法工厂
 * @param exp 正则表达式
 * @param options Completion数组(无需过滤)
 * @returns {(function(*): (null|{options: *, from: number|number}))|*}
 */
export const matcherFactory = (exp, options) => (context) => {
    let word = context.matchBefore(exp);
    if (!word && !context.explicit) return null;
    return {
        from: word.from ? word.from : context.pos,
        options,
    };
}
/**
 * 自动完成的apply函数工厂, 使用 "前缀+占位文本+后缀" 替换指定文本,并选中占位文本
 * @param prefix 前缀文本
 * @param suffix 后缀文本
 * @param text 中间的占位文本
 * @returns {(function(*, *, *, *): void)|*}
 */
export const applyFactory = (prefix = "", suffix = "", text = "{占位文本}") => (view, completion, from, to) => {
    const insert = prefix + text + suffix;
    const offset = insert.indexOf(text);
    const anchor = from + offset;
    const head = anchor + text.length
    // 插入文字并选中占位文本
    view.dispatch({
        changes: {from, to, insert}, selection: EditorSelection.range(anchor, head)
    })
}

/**
 * 自动完成类型
 */
export class CompletionType {
    // 无参
    static NO_PARAM = 0;
    // 可以有参
    static HAS_PARAM = 1;
    // 必须传参
    static REQUIRED_PARAM = 2;

}

//其他论坛标签定义
export const bbsCodes = [
    // name:标签的名称 detail:标签含义  options:参数必须从其中选择 text:占位文本, paramText:参数的占位文本
    {
        name: "align",
        detail: "对齐方式",
        param: CompletionType.REQUIRED_PARAM,
        options: [{label: "左对齐", value: "left"}, {label: "右对齐", value: "right"}, {label: "居中", value: "center"},]
    },
    {name: "code", detail: "代码框", param: CompletionType.REQUIRED_PARAM, text: "代码", options: ["c", "php", "js", "xml", "py", "lua"]},
    {name: "uid", detail: "用户链接", param: CompletionType.REQUIRED_PARAM, text: "用户名", paramText: '用户UID'},
    {name: "tid", detail: "主题链接", param: CompletionType.REQUIRED_PARAM, text: "链接标题", paramText: '主题TID'},
    {name: "pid", detail: "回复链接", param: CompletionType.REQUIRED_PARAM, text: "链接标题", paramText: '回复PID'},
    {name: "collapse", detail: "折叠", param: CompletionType.HAS_PARAM, text: "折叠内容", paramText: '折叠标题'},
    {name: "url", detail: "链接", param: CompletionType.HAS_PARAM, text: "链接标题", paramText: '链接地址'},
    {name: "del", detail: "删除线", param: CompletionType.NO_PARAM},
    {name: "b", detail: "粗体", param: CompletionType.NO_PARAM},
    {name: "u", detail: "下划线", param: CompletionType.NO_PARAM},
    {name: "i", detail: "斜体", param: CompletionType.NO_PARAM},
    {name: "h", detail: "标题", param: CompletionType.NO_PARAM, text: '标题'},
    {name: "list", detail: "列表", param: CompletionType.NO_PARAM, text: '\n[*]列表项\n'},
    {name: "quote", detail: "引用框", param: CompletionType.NO_PARAM},
    {name: "table", detail: "表格", param: CompletionType.NO_PARAM, text: '内容为tr标签'},
    {name: "tr", detail: "表格行", param: CompletionType.NO_PARAM, text: '内容为td标签'},
    {name: "td", detail: "单元格", param: CompletionType.NO_PARAM,},
    {name: "dice", detail: "骰子", param: CompletionType.NO_PARAM, text: "格式为: 骰子数量d骰子面数"},
]
// 论坛标签的自动完成数据
export const bbsCodeCompletion = bbsCodes.flatMap(item => {
    const {name, detail, info, param, options, text, paramText} = item
    if (param === CompletionType.NO_PARAM) {
        // 无参代码
        return [{
            label: `[${name}]`,
            detail, info,
            apply: applyFactory(`[${name}]`, `[/${name}`, text)
        }]
    }
    if (param === CompletionType.HAS_PARAM) {
        // 有参代码
        return [{
            label: `[${name}]`,
            detail, info,
            apply: applyFactory(`[${name}=${paramText}]`, `[/${name}`, text)
        }]
    }
    if (param === CompletionType.REQUIRED_PARAM) {
        // 必须传参
        if (options) {
            //有选项
            return options.map(item => {
                if (typeof item === 'string') {
                    //项目是字符串
                    return {
                        label: `[${name}=${item}]`,
                        detail, info,
                        apply: applyFactory(`[${name}=${item}]`, `[/${name}`, text)
                    }
                } else if (typeof item === 'object') {
                    //项目是对象
                    const {label, value} = item
                    return {
                        label: `[${name}=${value}]`,
                        detail: label, info,
                        apply: applyFactory(`[${name}=${value}]`, `[/${name}`, text)
                    }
                }
            })
        } else {
            //无选项
            return [{
                label: `[${name}]`,
                detail, info,
                apply: applyFactory(`[${name}=${paramText}]`, `[/${name}`, text)
            }]
        }
    }

    return []
})